package com.xin.di.uav.applet.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.xin.di.uav.applet.mapper.NewUserMapper;
import com.xin.di.uav.applet.mapper.PermissionMapper;
import com.xin.di.uav.applet.mapper.SysRolePermissionMapper;
import com.xin.di.uav.applet.po.UserAccountPO;
import com.xin.di.uav.applet.request.ServiceAreaAddParam;
import com.xin.di.uav.applet.request.ServiceAreaEditParam;
import com.xin.di.uav.applet.resp.UserResp;
import com.xin.di.uav.applet.service.NewUserService;
import com.xin.di.uav.common.awt.JwtUtil;
import com.xin.di.uav.common.exception.BusinessException;
import com.xin.di.uav.common.request.common.IdRequest;
import com.xin.di.uav.common.response.IdAndNameResp;
import com.xin.di.uav.common.response.MenuTreeResp;
import com.xin.di.uav.common.response.TreeResp;
import com.xin.di.uav.common.utils.BeanUtil;
import com.xin.di.uav.common.utils.PhoneEncoderUtil;
import com.xin.di.uav.common.utils.TreeNodeTree;
import com.xin.di.uav.operate.mapper.UserRoleMapper;
import com.xin.di.uav.operate.po.PermissionPO;
import com.xin.di.uav.operate.po.ServiceAreaPO;
import com.xin.di.uav.applet.mapper.UserAccountsMapper;
import com.xin.di.uav.operate.po.SysRolePermissionPO;
import com.xin.di.uav.operate.po.UserRolePO;
import com.xin.di.uav.user.entity.UserExtra;
import com.xin.di.uav.user.mapper.UserExtraMapper;
import com.xin.di.uav.user.po.UserPO;
import jakarta.annotation.Resource;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import jakarta.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class NewUserServiceImpl implements NewUserService {
    @Autowired
    private NewUserMapper userMapper;


    @Resource(name = "exportPoolExecutor")
    private Executor exportTaskExecutor;

    @Autowired
    private UserAccountsMapper userAccountsMapper;

    @Autowired
    private UserExtraMapper userExtraMapper;

    @Value("${download.tmp.dir:/tmp/excel_export_}")
    private String tmpBaseDir;
    @Autowired
    private NewUserMapper newUserMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private SysRolePermissionMapper sysRolePermissionMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public boolean add(ServiceAreaAddParam serviceArea) {
        ServiceAreaPO serviceAreaPO = BeanUtil.copyProperties(serviceArea, ServiceAreaPO.class);
        serviceAreaPO.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        return userMapper.insert(serviceAreaPO) > 0;
    }

    @Override
    public boolean delete(String id) {
        return userMapper.deleteById(id) > 0;
    }

    @Override
    public boolean update(ServiceAreaEditParam serviceArea) {
        String id = serviceArea.getId();
        UserPO serviceAreaPO = userMapper.selectById(id);
        if (serviceAreaPO == null) {
            throw new BusinessException("记录不存在");
        }
        serviceAreaPO = BeanUtil.copyProperties(serviceArea, UserPO.class);
        return userMapper.updateById(serviceAreaPO) > 0;
    }

    @Override
    public boolean updateStatus(IdRequest idRequest) {
        String id = idRequest.getId();
        UserPO userPO = userMapper.selectById(id);
        if (userPO == null) {
            throw new BusinessException("记录不存在");
        }
        boolean status = userPO.isStatus();
        userPO.setStatus(!status);
        return userMapper.updateById(userPO) > 0;
    }

    @Override
    public UserPO getById(String id) {
        return userMapper.selectById(id);
    }

    @Override
    public List<UserResp.Record> list(int pageNum, int pageSize, String phone, Date startTime, Date endTime) {
        pageNum = (pageNum - 1) * pageSize;
        int cnt = userMapper.count(phone, startTime, endTime);
        List<UserResp.Record> recordList = new ArrayList<>();
        if (cnt > 0) {
            List<UserPO> userPOS = userMapper.selectList(pageNum, pageSize, phone, startTime, endTime);
            List<String> userIds = userPOS.stream().map(UserPO::getId).toList();
            List<UserExtra> userExtras = userExtraMapper.selByUserIds(userIds);

            for (UserPO userPO : userPOS) {
                UserResp.Record record = BeanUtil.copyProperties(userPO, UserResp.Record.class);
                String oldPhone = record.getPhone();
                if (ObjectUtil.isNotEmpty(oldPhone) && oldPhone.length() == 11) {
                    record.setPhone(PhoneEncoderUtil.desensitization(oldPhone));
                }

                for (UserExtra userExtra : userExtras) {
                    if (userExtra.getUserId().equals(userPO.getId())) {
                        record.setLastLoginTime(userExtra.getLastLoginTime());
                    }
                }

                recordList.add(record);
            }
        }


        return recordList;
    }

    @Override
    public String loginByCode(String userName, String password) {

        UserAccountPO userAccountPO = userAccountsMapper.selectById(password, userName);
        if (userAccountPO == null) {
            throw new BusinessException("用户不存在或密码错误");
        }
        Map<String, Object> info = new HashMap<>(1);
        info.put("displayName", userAccountPO.getDisplayName());
        info.put("userId", userAccountPO.getId());
        //生成JWT字符串
        return JwtUtil.sign(userAccountPO.getId(), info);
    }

    @Override
    public void export(HttpServletResponse response, String phone, Date startTime, Date endTime) {

        // 1. 创建临时目录
        String tempDir = tmpBaseDir + System.currentTimeMillis();
        try {
            Files.createDirectories(Paths.get(tempDir));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        int total = newUserMapper.count(phone, startTime, endTime);
        int pageSize = 10000;
        int totalPages = total / pageSize + 1;
        // 2. 分页并行导出
        List<CompletableFuture<File>> futures = IntStream.range(0, totalPages).mapToObj(page -> CompletableFuture.supplyAsync(() -> {
            List<UserResp.Record> records = this.list(page + 1, pageSize, phone, startTime, endTime);
            for (UserResp.Record record : records) {
                record.setStatusString(record.isStatus() ? "正常" : "冻结");
            }
            String fileName = tempDir + "/用户列表_" + page + ".xlsx";
            try (FileOutputStream out = new FileOutputStream(fileName)) {
                EasyExcel.write(out, UserResp.Record.class).sheet("Sheet1").doWrite(records);
                return new File(fileName);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, exportTaskExecutor)).toList();

        // 3. 压缩所有文件
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment;filename=export.zip");

        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

            futures.forEach(future -> {
                try {
                    File file = future.get();
                    zos.putNextEntry(new ZipEntry(file.getName()));
                    Files.copy(file.toPath(), zos);
                    zos.closeEntry();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            // 4. 清理临时文件
            try {
                FileUtils.deleteDirectory(new File(tempDir));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public List<MenuTreeResp> getRoleInfo() {
        List<MenuTreeResp> treeList = new ArrayList<>();
        String userId = JwtUtil.getUserId();
        List<String> roleIds = userRoleMapper.selectByUserId(userId);
        if (CollectionUtil.isNotEmpty(roleIds)) {
            List<SysRolePermissionPO> sysRolePermissionPOS = sysRolePermissionMapper.selByIds(roleIds);
            if (CollectionUtil.isNotEmpty(sysRolePermissionPOS)) {
                List<String> ids = sysRolePermissionPOS.stream().map(SysRolePermissionPO::getPermissionId).toList();
                List<PermissionPO> permissionPOS = permissionMapper.selByIds(ids);
                if (CollectionUtil.isNotEmpty(permissionPOS)) {
                    List<PermissionPO> permissionPOS1 = permissionPOS.stream().filter(permissionPO -> ObjectUtils.isNotEmpty(permissionPO.getPermType()) && permissionPO.getPermType() == 1).toList();
                    List<MenuTreeResp> treeRespList = new ArrayList<>();
                    if (CollectionUtil.isNotEmpty(permissionPOS1)) {
                        for (PermissionPO permission : permissionPOS1) {
                            MenuTreeResp treeResp = BeanUtil.copyProperties(permission, MenuTreeResp.class);
                            treeResp.setTitle(permission.getPermName());
                            treeRespList.add(treeResp);
                        }
                        return treeRespList.stream().filter(node -> ObjectUtils.isEmpty(node.getParentId())).peek(root -> root.setChildren(getChildren(root, treeRespList))).collect(Collectors.toList());
                    }
                }
            }

        }
        return treeList;
    }


    private static List<MenuTreeResp> getChildren(MenuTreeResp parent, List<MenuTreeResp> list) {
        List<MenuTreeResp> children = list.stream().filter(node -> parent.getId().equals(node.getParentId())).peek(child -> child.setChildren(getChildren(child, list))).collect(Collectors.toList());
        return children.isEmpty() ? null : children;
    }
}


